/** @noSelfInFile **/

import {OrderId} from "../globals/order";
import {Destructable} from "./destructable";
import {Force} from "./force";
import {Group} from "./group";
import {Handle} from "./handle";
import {Item} from "./item";
import {MapPlayer} from "./player";
import {Point} from "./point";
import {Sound} from "./sound";
import {Widget} from "./widget";
import {Entity} from "../../ecs/Ecs";
import UnitUtil from "../../util/UnitUtil";
import DataBase from "../../common/DataBase";
import TextTagUtil from "../../util/TextTagUtil";
import {TextTag} from "./texttag";

let unitEntityMap: { [id: number]: Entity } = {}

export class Unit extends Widget {


    public readonly handle!: unit;

    constructor(owner: number, unitId: number, x: number, y: number, face: number) {
        if (Handle.initFromHandle()) {
            super();
            return;
        }
        const p = Player(owner);
        const unitH = CreateUnit(p, unitId, x, y, face)
        super(unitH);
    }

    public get solarData(): { [key: string]: any } {
        return DataBase.getData("Unit", this.handle)
    }

    //
    /**
     *  addons
     */
    public costLife(val: number): boolean {
        if (this.life < val) {
            return false
        }
        this.life = this.life - val
        return true
    }

    public costMana(val: number): boolean {
        if (this.mana < val) {
            return false
        }
        this.mana = this.mana - val
        return true
    }

    public textTag(text: string, red: number = 0, green: number = 200, blue: number = 0): TextTag {
        return TextTagUtil.textOnUnit(this.handle, text, red, green, blue)
    }


    /**
     *  unitEntityMap
     */
    public set entity(value: Entity) {
        unitEntityMap[this.id] = value
    }

    public get entity(): Entity {
        return unitEntityMap[this.id];
    }

    //o
    public set acquireRange(value: number) {
        SetUnitAcquireRange(this.handle, value);
    }

    public get acquireRange() {
        return GetUnitAcquireRange(this.handle);
    }

    public get agility() {
        return GetHeroAgi(this.handle, false);
    }

    public set agility(value: number) {
        SetHeroAgi(this.handle, value, true);
    }

    // public get armor() {
    //     return BlzGetUnitArmor(this.handle);
    // }
    //
    // public set armor(armorAmount: number) {
    //     BlzSetUnitArmor(this.handle, armorAmount);
    // }

    public set canSleep(flag: boolean) {
        UnitAddSleep(this.handle, flag);
    }

    public get canSleep() {
        return UnitCanSleep(this.handle);
    }

    // public get collisionSize() {
    //     return BlzGetUnitCollisionSize(this.handle);
    // }

    public set color(whichColor: playercolor) {
        SetUnitColor(this.handle, whichColor);
    }

    public get currentOrder() {
        return GetUnitCurrentOrder(this.handle);
    }

    public get defaultAcquireRange() {
        return GetUnitDefaultAcquireRange(this.handle);
    }

    public get defaultFlyHeight() {
        return GetUnitDefaultFlyHeight(this.handle);
    }

    public get defaultMoveSpeed() {
        return GetUnitDefaultMoveSpeed(this.handle);
    }

    public get defaultPropWindow() {
        return GetUnitDefaultPropWindow(this.handle);
    }

    public get defaultTurnSpeed() {
        return GetUnitDefaultTurnSpeed(this.handle);
    }

    public get experience() {
        return GetHeroXP(this.handle);
    }

    public set experience(newXpVal: number) {
        SetHeroXP(this.handle, newXpVal, true);
    }

    public set facing(value: number) {
        SetUnitFacing(this.handle, value);
    }

    public get facing() {
        return GetUnitFacing(this.handle);
    }

    public get foodMade() {
        return GetUnitFoodMade(this.handle);
    }

    public get foodUsed() {
        return GetUnitFoodUsed(this.handle);
    }

    public get ignoreAlarmToggled() {
        return UnitIgnoreAlarmToggled(this.handle);
    }

    public get intelligence() {
        return GetHeroInt(this.handle, false);
    }

    public set intelligence(value: number) {
        SetHeroInt(this.handle, value, true);
    }

    public get inventorySize() {
        return UnitInventorySize(this.handle);
    }

    public set invulnerable(flag: boolean) {
        SetUnitInvulnerable(this.handle, flag);
    }

    // public get invulnerable() {
    //     return BlzIsUnitInvulnerable(this.handle);
    // }

    public get level() {
        return GetUnitLevel(this.handle);
    }

    //
    // public get localZ() {
    //     return BlzGetLocalUnitZ(this.handle);
    // }

    public get mana() {
        return this.getState(UNIT_STATE_MANA);
    }

    public set mana(value: number) {
        this.setState(UNIT_STATE_MANA, value);
    }

    // public get maxLife() {
    //     return BlzGetUnitMaxHP(this.handle);
    // }
    //
    // public set maxLife(value: number) {
    //     BlzSetUnitMaxHP(this.handle, value);
    // }
    //
    // public get maxMana() {
    //     return BlzGetUnitMaxMana(this.handle);
    // }
    //
    // public set maxMana(value: number) {
    //     BlzSetUnitMaxMana(this.handle, value);
    // }

    public set moveSpeed(value: number) {
        SetUnitMoveSpeed(this.handle, value);
    }

    public get moveSpeed() {
        return GetUnitMoveSpeed(this.handle);
    }

    get name() {
        return GetUnitName(this.handle);
    }

    // set name(value: string) {
    //     BlzSetUnitName(this.handle, value);
    // }
    //
    // public set nameProper(value: string) {
    //     BlzSetHeroProperName(this.handle, value);
    // }

    public get nameProper() {
        return GetHeroProperName(this.handle);
    }

    public set owner(whichPlayer: MapPlayer) {
        SetUnitOwner(this.handle, whichPlayer.handle, true);
    }

    public get owner() {
        return MapPlayer.fromHandle(GetOwningPlayer(this.handle));
    }

    public set paused(flag: boolean) {
        PauseUnit(this.handle, flag);
    }

    public get paused() {
        return IsUnitPaused(this.handle);
    }

    public get point() {
        return Point.fromHandle(GetUnitLoc(this.handle));
    }

    public set point(whichPoint: Point) {
        SetUnitPositionLoc(this.handle, whichPoint.handle);
    }

    public get pointValue() {
        return GetUnitPointValue(this.handle);
    }

    public set propWindow(value: number) {
        SetUnitPropWindow(this.handle, value);
    }

    public get propWindow() {
        return GetUnitPropWindow(this.handle);
    }

    public get race() {
        return GetUnitRace(this.handle);
    }

    public get rallyDestructable() {
        return Destructable.fromHandle(GetUnitRallyDestructable(this.handle));
    }

    public get rallyPoint() {
        return Point.fromHandle(GetUnitRallyPoint(this.handle));
    }

    public get rallyUnit() {
        return Unit.fromHandle(GetUnitRallyUnit(this.handle));
    }

    public set resourceAmount(amount: number) {
        SetResourceAmount(this.handle, amount);
    }

    public get resourceAmount() {
        return GetResourceAmount(this.handle);
    }

    // public get selectable() {
    //     return BlzIsUnitSelectable(this.handle);
    // }
    //
    // public set selectionScale(scale: number) {
    //     this.setField(UNIT_RF_SELECTION_SCALE, scale);
    // }
    //
    // public get selectionScale() {
    //     const result = this.getField(UNIT_RF_SELECTION_SCALE);
    //     return typeof result === "number" ? result : 0;
    // }

    public set show(flag: boolean) {
        ShowUnit(this.handle, flag);
    }

    public get show() {
        return !IsUnitHidden(this.handle);
    }

    // public get skin() {
    //     return BlzGetUnitSkin(this.handle);
    // }
    //
    // public set skin(skinId: number) {
    //     BlzSetUnitSkin(this.handle, skinId);
    // }

    public get skillPoints() {
        return GetHeroSkillPoints(this.handle);
    }

    public set skillPoints(skillPointDelta: number) {
        UnitModifySkillPoints(this.handle, skillPointDelta);
    }

    public get sleeping() {
        return UnitIsSleeping(this.handle);
    }

    public get strength() {
        return GetHeroStr(this.handle, false);
    }

    public set strength(value: number) {
        SetHeroStr(this.handle, value, true);
    }

    public set turnSpeed(value: number) {
        SetUnitTurnSpeed(this.handle, value);
    }

    public get turnSpeed() {
        return GetUnitTurnSpeed(this.handle);
    }

    public get typeId() {
        return GetUnitTypeId(this.handle);
    }

    public get typeIdString() {
        return id2string(GetUnitTypeId(this.handle));
    }

    public get userData() {
        return GetUnitUserData(this.handle);
    }

    public set userData(value: number) {
        SetUnitUserData(this.handle, value);
    }

    public set waygateActive(flag: boolean) {
        WaygateActivate(this.handle, flag);
    }

    public get waygateActive() {
        return WaygateIsActive(this.handle);
    }

    public get x() {
        return GetUnitX(this.handle);
    }

    public set x(value: number) {
        SetUnitX(this.handle, value);
    }

    public get y() {
        return GetUnitY(this.handle);
    }

    public set y(value: number) {
        SetUnitY(this.handle, value);
    }

    // public get z() {
    //     return BlzGetUnitZ(this.handle);
    // }

    public addAbility(abilityId: number) {
        return UnitAddAbility(this.handle, abilityId);
    }

    public addAnimationProps(animProperties: string, add: boolean) {
        AddUnitAnimationProperties(this.handle, animProperties, add);
    }

    public addExperience(xpToAdd: number, showEyeCandy: boolean) {
        AddHeroXP(this.handle, xpToAdd, showEyeCandy);
    }

    public addIndicator(red: number, blue: number, green: number, alpha: number) {
        UnitAddIndicator(this.handle, red, blue, green, alpha);
    }

    public addItem(whichItem: Item) {
        return UnitAddItem(this.handle, whichItem.handle);
    }

    public addItemById(itemId: number) {
        return Item.fromHandle(UnitAddItemById(this.handle, itemId));
    }

    public addItemToSlotById(itemId: number, itemSlot: number) {
        return UnitAddItemToSlotById(this.handle, itemId, itemSlot);
    }

    public addItemToStock(itemId: number, currentStock: number, stockMax: number) {
        AddItemToStock(this.handle, itemId, currentStock, stockMax);
    }

    public addResourceAmount(amount: number) {
        AddResourceAmount(this.handle, amount);
    }

    public addSleepPerm(add: boolean) {
        UnitAddSleepPerm(this.handle, add);
    }

    public addType(whichUnitType: unittype) {
        return UnitAddType(this.handle, whichUnitType);
    }

    public addUnitToStock(unitId: number, currentStock: number, stockMax: number) {
        AddUnitToStock(this.handle, unitId, currentStock, stockMax);
    }

    public applyTimedLife(buffId: number, duration: number) {
        UnitApplyTimedLife(this.handle, buffId, duration);
    }

    public attachSound(sound: Sound) {
        AttachSoundToUnit(sound.handle, this.handle);
    }

    // public cancelTimedLife() {
    //     BlzUnitCancelTimedLife(this.handle);
    // }

    public canSleepPerm() {
        return UnitCanSleepPerm(this.handle);
    }

    public countBuffs(removePositive: boolean, removeNegative: boolean, magic: boolean, physical: boolean, timedLife: boolean, aura: boolean, autoDispel: boolean) {
        return UnitCountBuffsEx(this.handle, removePositive, removeNegative, magic, physical, timedLife, aura, autoDispel);
    }

    public damageAt(delay: number, radius: number, x: number, y: number, amount: number, attack: boolean, ranged: boolean, attackType: attacktype, damageType: damagetype, weaponType: weapontype) {
        return UnitDamagePoint(this.handle, delay, radius, x, y, amount, attack, ranged, attackType, damageType, weaponType);
    }

    public damageTarget(target: widget, amount: number, attack: boolean, ranged: boolean, attackType: attacktype, damageType: damagetype, weaponType: weapontype) {
        return UnitDamageTarget(this.handle, target, amount, attack, ranged, attackType, damageType, weaponType);
    }

    public decAbilityLevel(abilCode: number) {
        return DecUnitAbilityLevel(this.handle, abilCode);
    }

    /**
     * Instantly removes the unit from the game.
     */
    public destroy() {
        DataBase.getData("Unit", this.handle)
        RemoveUnit(this.handle);
    }

    // public disableAbility(abilId: number, flag: boolean, hideUI: boolean) {
    //     BlzUnitDisableAbility(this.handle, abilId, flag, hideUI);
    // }

    public dropItem(whichItem: Item, x: number, y: number) {
        return UnitDropItemPoint(this.handle, whichItem.handle, x, y);
    }

    public dropItemFromSlot(whichItem: Item, slot: number) {
        return UnitDropItemSlot(this.handle, whichItem.handle, slot);
    }

    public dropItemTarget(whichItem: Item, target: Widget/* | Unit | Item | Destructable*/) {
        return UnitDropItemTarget(this.handle, whichItem.handle, target.handle);
    }

    // public endAbilityCooldown(abilCode: number) {
    //     BlzEndUnitAbilityCooldown(this.handle, abilCode);
    // }
    //
    // public getAbility(abilId: number) {
    //     return BlzGetUnitAbility(this.handle, abilId);
    // }
    //
    // public getAbilityByIndex(index: number) {
    //     return BlzGetUnitAbilityByIndex(this.handle, index);
    // }
    //
    // public getAbilityCooldown(abilId: number, level: number) {
    //     return BlzGetUnitAbilityCooldown(this.handle, abilId, level);
    // }
    //
    // public getAbilityCooldownRemaining(abilId: number) {
    //     return BlzGetUnitAbilityCooldownRemaining(this.handle, abilId);
    // }

    public hasAbility(abilId: string): boolean {
        return GetUnitAbilityLevel(this.handle, FourCC(abilId)) > 0;
    }

    public getAbilityLevel(abilCode: number) {
        return GetUnitAbilityLevel(this.handle, abilCode);
    }

    // public getAbilityManaCost(abilId: number, level: number) {
    //     return BlzGetUnitAbilityManaCost(this.handle, abilId, level);
    // }

    public getAgility(includeBonuses: boolean) {
        return GetHeroAgi(this.handle, includeBonuses);
    }

    // public getAttackCooldown(weaponIndex: number) {
    //     return BlzGetUnitAttackCooldown(this.handle, weaponIndex);
    // }
    //
    // public getBaseDamage(weaponIndex: number) {
    //     return BlzGetUnitBaseDamage(this.handle, weaponIndex);
    // }
    //
    // public getDiceNumber(weaponIndex: number) {
    //     return BlzGetUnitDiceNumber(this.handle, weaponIndex);
    // }
    //
    // public getDiceSides(weaponIndex: number) {
    //     return BlzGetUnitDiceSides(this.handle, weaponIndex);
    // }

    // public getField(field: unitbooleanfield | unitintegerfield | unitrealfield | unitstringfield) {
    //     const fieldType = field.toString().substr(0, field.toString().indexOf(":"));
    //
    //     switch (fieldType) {
    //         case "unitbooleanfield":
    //             const fieldBool: unitbooleanfield = field as unitbooleanfield;
    //
    //             return BlzGetUnitBooleanField(this.handle, fieldBool);
    //         case "unitintegerfield":
    //             const fieldInt: unitintegerfield = field as unitintegerfield;
    //
    //             return BlzGetUnitIntegerField(this.handle, fieldInt);
    //         case "unitrealfield":
    //             const fieldReal: unitrealfield = field as unitrealfield;
    //
    //             return BlzGetUnitRealField(this.handle, fieldReal);
    //         case "unitstringfield":
    //             const fieldString: unitstringfield = field as unitstringfield;
    //
    //             return BlzGetUnitStringField(this.handle, fieldString);
    //         default:
    //             return 0;
    //     }
    // }

    public getflyHeight() {
        return GetUnitFlyHeight(this.handle);
    }

    public getHeroLevel() {
        return GetHeroLevel(this.handle);
    }

    public getIgnoreAlarm(flag: boolean) {
        return UnitIgnoreAlarm(this.handle, flag);
    }

    public getIntelligence(includeBonuses: boolean) {
        return GetHeroInt(this.handle, includeBonuses);
    }

    public getItemInSlot(slot: number) {
        let itemHandle = UnitItemInSlot(this.handle, slot);
        if (itemHandle == null) {
            return null;
        }
        return Item.fromHandle(itemHandle);
    }

    public getItemByItemType(itemtype: number) {
        let itemHandle = UnitUtil.GetInventoryOfItemType(this.handle, itemtype)
        if (itemHandle) {
            return Item.fromHandle(itemHandle);
        }
        return null;
    }

    public getState(whichUnitState: unitstate) {
        return GetUnitState(this.handle, whichUnitState);
    }

    public getStrength(includeBonuses: boolean) {
        return GetHeroStr(this.handle, includeBonuses);
    }

    public hasBuffs(removePositive: boolean, removeNegative: boolean, magic: boolean, physical: boolean, timedLife: boolean, aura: boolean, autoDispel: boolean) {
        return UnitHasBuffsEx(this.handle, removePositive, removeNegative, magic, physical, timedLife, aura, autoDispel);
    }

    public hasItem(whichItem: Item) {
        return UnitHasItem(this.handle, whichItem.handle);
    }

    // public hideAbility(abilId: number, flag: boolean) {
    //     BlzUnitHideAbility(this.handle, abilId, flag);
    // }

    public incAbilityLevel(abilCode: number) {
        return IncUnitAbilityLevel(this.handle, abilCode);
    }

    public inForce(whichForce: Force) {
        return IsUnitInForce(this.handle, whichForce.handle);
    }

    public inGroup(whichGroup: Group) {
        return IsUnitInGroup(this.handle, whichGroup.handle);
    }

    public inRange(x: number, y: number, distance: number) {
        return IsUnitInRangeXY(this.handle, x, y, distance);
    }

    public inRangeOfPoint(whichPoint: Point, distance: number) {
        return IsUnitInRangeLoc(this.handle, whichPoint.handle, distance);
    }

    public inRangeOfUnit(otherUnit: Unit, distance: number) {
        return IsUnitInRange(this.handle, otherUnit.handle, distance);
    }

    // public interruptAttack() {
    //     BlzUnitInterruptAttack(this.handle);
    // }

    public inTransport(whichTransport: Unit) {
        return IsUnitInTransport(this.handle, whichTransport.handle);
    }

    public isAlive(): boolean {
        // return UnitAlive(this.handle);
        return this.getState(UNIT_STATE_LIFE) >= 1;
    }

    public isAlly(whichPlayer: MapPlayer) {
        return IsUnitAlly(this.handle, whichPlayer.handle);
    }

    public isEnemy(whichPlayer: MapPlayer) {
        return IsUnitEnemy(this.handle, whichPlayer.handle);
    }

    public isExperienceSuspended() {
        return IsSuspendedXP(this.handle);
    }

    public isFogged(whichPlayer: MapPlayer) {
        return IsUnitFogged(this.handle, whichPlayer.handle);
    }

    public isHero() {
        return IsHeroUnitId(this.typeId);
    }

    public isIllusion() {
        return IsUnitIllusion(this.handle);
    }

    public isLoaded() {
        return IsUnitLoaded(this.handle);
    }

    public isMasked(whichPlayer: MapPlayer) {
        return IsUnitMasked(this.handle, whichPlayer.handle);
    }

    public isSelected(whichPlayer: MapPlayer) {
        return IsUnitSelected(this.handle, whichPlayer.handle);
    }

    public issueBuildOrder(unit: string | number, x: number, y: number) {
        return typeof unit === "string" ? IssueBuildOrder(this.handle, unit, x, y) : IssueBuildOrderById(this.handle, unit, x, y);
    }

    public issueImmediateOrder(order: string | OrderId) {
        return typeof order === "string" ? IssueImmediateOrder(this.handle, order) : IssueImmediateOrderById(this.handle, order);
    }

    public issueInstantOrderAt(order: string | OrderId, x: number, y: number, instantTargetWidget: Widget) {
        return typeof order === "string" ? IssueInstantPointOrder(this.handle, order, x, y, instantTargetWidget.handle) : IssueInstantPointOrderById(this.handle, order, x, y, instantTargetWidget.handle);
    }

    public issueInstantTargetOrder(order: string | OrderId, targetWidget: Widget, instantTargetWidget: Widget) {
        return typeof order === "string" ? IssueInstantTargetOrder(this.handle, order, targetWidget.handle, instantTargetWidget.handle) : IssueInstantTargetOrderById(this.handle, order, targetWidget.handle, instantTargetWidget.handle);
    }

    public issueOrderAt(order: string | OrderId, x: number, y: number) {
        return typeof order === "string" ? IssuePointOrder(this.handle, order, x, y) : IssuePointOrderById(this.handle, order, x, y);
    }

    public issuePointOrder(order: string | OrderId, whichPoint: Point) {
        return typeof order === "string" ? IssuePointOrderLoc(this.handle, order, whichPoint.handle) : IssuePointOrderByIdLoc(this.handle, order, whichPoint.handle);
    }

    public issueTargetOrder(order: string | OrderId, targetWidget: Widget) {
        return typeof order === "string" ? IssueTargetOrder(this.handle, order, targetWidget.handle) : IssueTargetOrderById(this.handle, order, targetWidget.handle);
    }

    public isUnit(whichSpecifiedUnit: Unit) {
        return IsUnit(this.handle, whichSpecifiedUnit.handle);
    }

    public isUnitType(whichUnitType: unittype) {
        return IsUnitType(this.handle, whichUnitType);
    }

    public isVisible(whichPlayer: MapPlayer) {
        return IsUnitVisible(this.handle, whichPlayer.handle);
    }

    /**
     * Kills the unit.
     */
    public kill() {
        KillUnit(this.handle);
    }

    public lookAt(whichBone: string, lookAtTarget: Unit, offsetX: number, offsetY: number, offsetZ: number) {
        SetUnitLookAt(this.handle, whichBone, lookAtTarget.handle, offsetX, offsetY, offsetZ);
    }

    public makeAbilityPermanent(permanent: boolean, abilityId: number) {
        UnitMakeAbilityPermanent(this.handle, permanent, abilityId);
    }

    public modifySkillPoints(skillPointDelta: number) {
        return UnitModifySkillPoints(this.handle, skillPointDelta);
    }

    // public pauseEx(flag: boolean) {
    //     BlzPauseUnitEx(this.handle, flag);
    // }

    public pauseTimedLife(flag: boolean) {
        UnitPauseTimedLife(this.handle, flag);
    }

    public queueAnimation(whichAnimation: string) {
        QueueUnitAnimation(this.handle, whichAnimation);
    }

    public recycleGuardPosition() {
        RecycleGuardPosition(this.handle);
    }

    public removeAbility(abilityId: number) {
        return UnitRemoveAbility(this.handle, abilityId);
    }

    public removeBuffs(removePositive: boolean, removeNegative: boolean) {
        UnitRemoveBuffs(this.handle, removePositive, removeNegative);
    }

    public removeBuffsEx(removePositive: boolean, removeNegative: boolean, magic: boolean, physical: boolean, timedLife: boolean, aura: boolean, autoDispel: boolean) {
        UnitRemoveBuffsEx(this.handle, removePositive, removeNegative, magic, physical, timedLife, aura, autoDispel);
    }

    public removeGuardPosition() {
        RemoveGuardPosition(this.handle);
    }

    public removeItem(whichItem: Item) {
        UnitRemoveItem(this.handle, whichItem.handle);
    }

    public removeItemFromSlot(itemSlot: number) {
        return Item.fromHandle(UnitRemoveItemFromSlot(this.handle, itemSlot));
    }

    public removeItemFromStock(itemId: number) {
        RemoveItemFromStock(this.handle, itemId);
    }

    public removeType(whichUnitType: unittype) {
        return UnitAddType(this.handle, whichUnitType);
    }

    public removeUnitFromStock(itemId: number) {
        RemoveUnitFromStock(this.handle, itemId);
    }

    public resetCooldown() {
        UnitResetCooldown(this.handle);
    }

    public resetLookAt() {
        ResetUnitLookAt(this.handle);
    }

    public revive(x: number, y: number, doEyecandy: boolean) {
        return ReviveHero(this.handle, x, y, doEyecandy);
    }

    public reviveAtPoint(whichPoint: Point, doEyecandy: boolean) {
        return ReviveHeroLoc(this.handle, whichPoint.handle, doEyecandy);
    }

    public select(flag: boolean) {
        SelectUnit(this.handle, flag);
    }

    public selectSkill(abilCode: number) {
        SelectHeroSkill(this.handle, abilCode);
    }

    // public setAbilityCooldown(abilId: number, level: number, cooldown: number) {
    //     BlzSetUnitAbilityCooldown(this.handle, abilId, level, cooldown);
    // }

    public setAbilityLevel(abilCode: number, level: number) {
        return SetUnitAbilityLevel(this.handle, abilCode, level);
    }

    // public setAbilityManaCost(abilId: number, level: number, manaCost: number) {
    //     BlzSetUnitAbilityManaCost(this.handle, abilId, level, manaCost);
    // }

    public setAgility(value: number, permanent: boolean) {
        SetHeroAgi(this.handle, value, permanent);
    }

    public setAnimation(whichAnimation: string | number) {
        if (typeof whichAnimation === "string") {
            SetUnitAnimation(this.handle, whichAnimation);
        } else {
            SetUnitAnimationByIndex(this.handle, whichAnimation);
        }
    }

    public setAnimationWithRarity(whichAnimation: string, rarity: raritycontrol) {
        SetUnitAnimationWithRarity(this.handle, whichAnimation, rarity);
    }

    // public setAttackCooldown(cooldown: number, weaponIndex: number) {
    //     BlzSetUnitAttackCooldown(this.handle, cooldown, weaponIndex);
    // }
    //
    // public setBaseDamage(baseDamage: number, weaponIndex: number) {
    //     BlzSetUnitBaseDamage(this.handle, baseDamage, weaponIndex);
    // }

    public setBlendTime(timeScale: number) {
        SetUnitBlendTime(this.handle, timeScale);
    }

    public setConstructionProgress(constructionPercentage: number) {
        UnitSetConstructionProgress(this.handle, constructionPercentage);
    }

    public setCreepGuard(creepGuard: boolean) {
        SetUnitCreepGuard(this.handle, creepGuard);
    }

    // public setDiceNumber(diceNumber: number, weaponIndex: number) {
    //     BlzSetUnitDiceNumber(this.handle, diceNumber, weaponIndex);
    // }
    //
    // public setDiceSides(diceSides: number, weaponIndex: number) {
    //     BlzSetUnitDiceSides(this.handle, diceSides, weaponIndex);
    // }

    public setExperience(newXpVal: number, showEyeCandy: boolean) {
        SetHeroXP(this.handle, newXpVal, showEyeCandy);
    }

    public setExploded(exploded: boolean) {
        SetUnitExploded(this.handle, exploded);
    }

    // public setFacingEx(facingAngle: number) {
    //     BlzSetUnitFacingEx(this.handle, facingAngle);
    // }
    //
    // public setField(field: unitbooleanfield | unitintegerfield | unitrealfield | unitstringfield, value: boolean | number | string) {
    //     const fieldType = field.toString().substr(0, field.toString().indexOf(":"));
    //
    //     if (fieldType === "unitbooleanfield" && typeof value === "boolean") {
    //         return BlzSetUnitBooleanField(this.handle, field as unitbooleanfield, value);
    //     } else if (fieldType === "unitintegerfield" && typeof value === "number") {
    //         return BlzSetUnitIntegerField(this.handle, field as unitintegerfield, value);
    //     } else if (fieldType === "unitrealfield" && typeof value === "number") {
    //         return BlzSetUnitRealField(this.handle, field as unitrealfield, value);
    //     } else if (fieldType === "unitstringfield" && typeof value === "string") {
    //         return BlzSetUnitStringField(this.handle, field as unitstringfield, value);
    //     }
    //
    //     return false;
    // }

    public setflyHeight(value: number, rate: number) {
        SetUnitFlyHeight(this.handle, value, rate);
    }

    public setHeroLevel(level: number, showEyeCandy: boolean) {
        SetHeroLevel(this.handle, level, showEyeCandy);
    }

    public setIntelligence(value: number, permanent: boolean) {
        SetHeroInt(this.handle, value, permanent);
    }

    public setItemTypeSlots(slots: number) {
        SetItemTypeSlots(this.handle, slots);
    }

    public setOwner(whichPlayer: MapPlayer, changeColor: boolean) {
        SetUnitOwner(this.handle, whichPlayer.handle, changeColor);
    }

    public setPathing(flag: boolean) {
        SetUnitPathing(this.handle, flag);
    }

    public setPosition(x: number, y: number) {
        SetUnitPosition(this.handle, x, y);
    }

    public setRescuable(byWhichPlayer: MapPlayer, flag: boolean) {
        SetUnitRescuable(this.handle, byWhichPlayer.handle, flag);
    }

    public setRescueRange(range: number) {
        SetUnitRescueRange(this.handle, range);
    }

    public setScale(scaleX: number, scaleY: number, scaleZ: number) {
        SetUnitScale(this.handle, scaleX, scaleY, scaleZ);
    }

    public setState(whichUnitState: unitstate, newVal: number) {
        SetUnitState(this.handle, whichUnitState, newVal);
    }

    public setStrength(value: number, permanent: boolean) {
        SetHeroStr(this.handle, value, permanent);
    }

    public setTimeScale(timeScale: number) {
        SetUnitTimeScale(this.handle, timeScale);
    }

    // public setUnitAttackCooldown(cooldown: number, weaponIndex: number) {
    //     BlzSetUnitAttackCooldown(this.handle, cooldown, weaponIndex);
    // }

    public setUnitTypeSlots(slots: number) {
        SetUnitTypeSlots(this.handle, slots);
    }

    public setUpgradeProgress(upgradePercentage: number) {
        UnitSetUpgradeProgress(this.handle, upgradePercentage);
    }

    public setUseAltIcon(flag: boolean) {
        UnitSetUsesAltIcon(this.handle, flag);
    }

    public setUseFood(useFood: boolean) {
        SetUnitUseFood(this.handle, useFood);
    }

    public setVertexColor(red: number, green: number, blue: number, alpha: number) {
        SetUnitVertexColor(this.handle, red, green, blue, alpha);
    }

    public shareVision(whichPlayer: MapPlayer, share: boolean) {
        UnitShareVision(this.handle, whichPlayer.handle, share);
    }

    // public showTeamGlow(show: boolean) {
    //     BlzShowUnitTeamGlow(this.handle, show);
    // }

    // public startAbilityCooldown(abilCode: number, cooldown: number) {
    //     BlzStartUnitAbilityCooldown(this.handle, abilCode, cooldown);
    // }

    public stripLevels(howManyLevels: number) {
        return UnitStripHeroLevel(this.handle, howManyLevels);
    }

    public suspendDecay(suspend: boolean) {
        UnitSuspendDecay(this.handle, suspend);
    }

    public suspendExperience(flag: boolean) {
        SuspendHeroXP(this.handle, flag);
    }

    public useItem(whichItem: Item) {
        return UnitUseItem(this.handle, whichItem.handle);
    }

    public useItemAt(whichItem: Item, x: number, y: number) {
        return UnitUseItemPoint(this.handle, whichItem.handle, x, y);
    }

    public useItemTarget(whichItem: Item, target: Widget) {
        return UnitUseItemTarget(this.handle, whichItem.handle, target.handle);
    }

    public wakeUp() {
        UnitWakeUp(this.handle);
    }

    public waygateGetDestinationX() {
        return WaygateGetDestinationX(this.handle);
    }

    public waygateGetDestinationY() {
        return WaygateGetDestinationY(this.handle);
    }

    public waygateSetDestination(x: number, y: number) {
        WaygateSetDestination(this.handle, x, y);
    }

    public static foodMadeByType(unitId: number) {
        return GetFoodMade(unitId);
    }

    public static foodUsedByType(unitId: number) {
        return GetFoodUsed(unitId);
    }

    public static fromEnum() {
        return this.fromHandle(GetEnumUnit());
    }

    public static fromEvent() {
        return this.fromHandle(GetTriggerUnit());
    }

    public static fromHandle(handle: unit): Unit {
        return this.getObject(handle);
    }

    public static getPointValueByType(unitType: number) {
        return GetUnitPointValueByType(unitType);
    }

    public static isUnitIdHero(unitId: number) {
        return IsHeroUnitId(unitId);
    }

    public static isUnitIdType(unitId: number, whichUnitType: unittype) {
        return IsUnitIdType(unitId, whichUnitType);
    }
}
